package com.desire.test;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.junit.platform.commons.util.StringUtils;

import java.time.Duration;

/**
 * @author LittleDesire
 * @description
 * @date 2022-02-10 周四 10:28
 * @since 17
 */
public class _58_junit测试 {
    /**
     * @Test :表示方法是测试方法。但是与JUnit4的@Test不同，他的职责非常单一不能声明任何属性，
     * 拓展的测试将会由Jupiter提供额外测试
     * @ParameterizedTest :表示方法是参数化测试
     * @RepeatedTest :表示方法可重复执行
     * @DisplayName :为测试类或者测试方法设置展示名称
     * @BeforeEach :表示在每个单元测试之前执行
     * @AfterEach :表示在每个单元测试之后执行
     * @BeforeAll :表示在所有单元测试之前执行
     * @AfterAll :表示在所有单元测试之后执行
     * @Tag :表示单元测试类别，类似于JUnit4中的@Categories
     * @Disabled :表示测试类或测试方法不执行，类似于JUnit4中的@Ignore
     * @Timeout :表示测试方法运行如果超过了指定时间将会返回错误
     * @ExtendWith :为测试类或测试方法提供扩展类引用
     * 测试参数
     * 利用@ValueSource等注解，指定入参，我们将可以使用不同的参数进行多次单元测试，
     * 而不需要每新增一个参数就新增一个单元测试，省去了很多冗余代码。
     * @ValueSource: 为参数化测试指定入参来源，支持八大基础类以及String类型,Class类型
     * @NullSource: 表示为参数化测试提供一个null的入参
     * @EnumSource: 表示为参数化测试提供一个枚举入参
     * <p>
     * 断言	                         描述
     * assertEquals(预期的，实际的)	预期不等于实际时失败
     * assertFalse(表达式)	        表达式不为假时失败
     * assertNull(实际)	            实际不为空时失败
     * assertNotNull(实际)	        当real为null时失败
     * assertAll()	                对许多断言进行分组，并且每个断言都会执行，即使其中一个或多个失败
     * assertTrue(表达式)            如果表达式不正确则失败
     * assertThrows()	            预期要测试的类将引发异常
     * <p>
     * 超时断言，Junit5还提供了Assertions.assertTimeout() 为测试方法设置了超时时间
     */
    @ParameterizedTest
    @ValueSource(strings = {"one", "two", "three"})
    @DisplayName("参数化测试1")
    public void parameterizedTest1(String string) {
        System.out.println(string);
        // StringUtils.isNotBlank(string)确定提供的字符串是否为空
        // .assertTrue()断言所提供的条件为真。
        Assertions.assertTrue(StringUtils.isNotBlank(string));
    }

    @ParameterizedTest
    @ValueSource(ints = 6)
    @DisplayName("参数化测试2")
    public void parameterizedTest1(int i) {
        System.out.println(i);
        // assertEquals（预期的，实际的）	预期不等于实际时失败
        Assertions.assertEquals(i * i, 38);
        /*
        6

        org.opentest4j.AssertionFailedError:
        Expected :36
        Actual   :38
         */
    }

    @Test
    @DisplayName("超时测试")
    public void timeoutTest() {
        //如果测试方法时间超过1s将会异常
        // org.opentest4j.AssertionFailedError: execution exceeded timeout of 1000 ms by 504 ms
        // 断言失败错误:执行超过1000ms的超时504 ms
        Assertions.assertTimeout(Duration.ofMillis(1000), () -> Thread.sleep(1500));
    }

    /**
     * 异常断言，在JUnit4时期，想要测试方法的异常情况时，需要用**@Rule注解的ExpectedException变量还是比较麻烦的。
     * 而JUnit5提供了一种新的断言方式Assertions.assertThrows()** ,配合函数式编程就可以进行使用。
     */
    @Test
    @DisplayName("异常测试")
    public void exceptionTest() {
        //扔出断言异常
        // Expected java.lang.ArithmeticException to be thrown, but nothing was thrown.
        // 断言失败错误: 预期的java.lang. arithmetics异常被抛出，但没有抛出任何东西。
        ArithmeticException arithmeticException = Assertions.assertThrows(ArithmeticException.class, () -> System.out.println(1 / 0));
        // 设置该抛出异常的名字
        arithmeticException.initCause(new Throwable("除数为零"));
        // 返回该可抛出对象的原因，如果原因不存在或未知，则返回null。
        System.out.println(arithmeticException.getCause().getMessage());
        // 返回此可抛出对象的详细消息字符串
        System.out.println(arithmeticException.getMessage());


    }
}
